package com.witmore.neutron.ai.web.wechat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.jk.mp.wx.client.WeChatClient;
import com.jk.mp.wx.config.WechatServiceProperties;
import com.jk.mp.wx.constant.WeChatAuthConstant;
import com.jk.mp.wx.response.BaseResponse;
import com.jk.mp.wx.response.WechatAuthAccessToken;
import com.witmore.neutron.ai.db.entity.UserDO;
import com.witmore.neutron.ai.db.mapper.UserMapper;
import com.witmore.neutron.ai.web.service.UserService;
import com.witmore.neutron.ai.web.wechat.dto.WechatUserInfo;
import com.witmore.neutron.ai.web.wechat.service.WechatOAuthService;
import com.witmore.neutron.ai.web.wechat.service.WechatTokenCacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;

/**
 * 微信网页授权服务实现类（仅处理code之后的步骤）
 * Author: 豆子高
 * Date: 2025/01/21
 */
@Slf4j
@Service
public class WechatOAuthServiceImpl implements WechatOAuthService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WeChatClient wechatClient;

    @Autowired
    private UserService userService;

    @Autowired
    private WechatServiceProperties wechatServiceProperties;

    @Autowired
    private WechatTokenCacheService wechatTokenCacheService;

    @Override
    public WechatAuthAccessToken getAccessToken(String code) {
        String url = String.format(WeChatAuthConstant.BUS_WECHAT_AUTH_GET_STABLE_TOKEN, wechatServiceProperties.getAppId(), wechatServiceProperties.getAppSecret(), code);

        try {
            log.info("请求微信access_token，URL: {}", url);

            WechatAuthAccessToken accessToken = wechatClient.executorGetHandler(WechatAuthAccessToken.class, url);

            if (accessToken == null) {
                throw new RuntimeException("获取微信access_token失败");
            }

            return accessToken;
        } catch (JsonProcessingException e) {
            log.error("解析微信access_token响应失败", e);
            throw new RuntimeException("解析微信access_token响应失败", e);
        } catch (Exception e) {
            log.error("请求微信access_token失败", e);
            throw new RuntimeException("请求微信access_token失败", e);
        }
    }

    @Override
    public WechatAuthAccessToken refreshAccessToken(String refreshToken) {
        String url = String.format(WeChatAuthConstant.BUS_WECHAT_REFRESH_TOKEN, wechatServiceProperties.getAppId(), refreshToken);

        try {
            log.info("刷新微信access_token，URL: {}", url);

            WechatAuthAccessToken accessToken = wechatClient.executorGetHandler(WechatAuthAccessToken.class, url);
            if (accessToken == null || accessToken.getErrcode() == null || !accessToken.isSuccess()) {
                log.error("刷新微信access_token失败: {}", accessToken == null ? "null" : accessToken.getErrMsg());
                throw new RuntimeException("刷新微信access_token失败: " + (accessToken == null ? "null" : accessToken.getErrMsg()));
            }
            return accessToken;
        } catch (JsonProcessingException e) {
            log.error("解析刷新微信access_token响应失败", e);
            throw new RuntimeException("解析刷新微信access_token响应失败", e);
        } catch (Exception e) {
            log.error("刷新微信access_token失败", e);
            throw new RuntimeException("刷新微信access_token失败", e);
        }
    }

    @Override
    public boolean isAccessTokenValid(String accessToken, String openid) {
        String url = String.format(WeChatAuthConstant.BUS_WECHAT_CHECK_TOKEN, accessToken, openid);
        try {
            log.info("验证微信access_token，URL: {}", url);
            BaseResponse baseResponse = wechatClient.executorGetHandler(BaseResponse.class, url);

            return baseResponse != null && baseResponse.getErrcode() != null && baseResponse.isSuccess();
        } catch (Exception e) {
            log.error("验证微信access_token失败", e);
            return false;
        }
    }

    @Override
    public WechatUserInfo getUserInfo(String accessToken, String openid) {
        String url = String.format(WeChatAuthConstant.BUS_WECHAT_GET_USER_INFO, accessToken, openid);

        try {
            log.info("请求微信用户信息，URL: {}", url);
            WechatUserInfo userInfo = wechatClient.executorGetHandler(WechatUserInfo.class, url);
            if (userInfo == null) {
                throw new RuntimeException("获取微信用户信息失败: " + "null");
            }
            return userInfo;
        } catch (JsonProcessingException e) {
            log.error("解析微信用户信息响应失败", e);
            throw new RuntimeException("解析微信用户信息响应失败", e);
        } catch (Exception e) {
            log.error("请求微信用户信息失败", e);
            throw new RuntimeException("请求微信用户信息失败", e);
        }
    }


    @Override
    public UserDO processWechatLogin(WechatUserInfo wechatUserInfo) {
        String openid = wechatUserInfo.getOpenid();
        if (!StringUtils.hasText(openid)) {
            throw new RuntimeException("微信openid为空");
        }

        // 根据openid查找用户
        UserDO existingUser = userMapper.selectOne(
                new LambdaQueryWrapper<UserDO>()
                        .eq(UserDO::getWxOpenid, openid)
        );

        if (existingUser != null) {
            // 用户已存在，更新最后登录时间
            existingUser.setLastLoginTime(LocalDateTime.now());
            existingUser.setUpdateTime(LocalDateTime.now());

            // 更新用户昵称（如果微信昵称有变化）
            if (StringUtils.hasText(wechatUserInfo.getNickname()) &&
                    !wechatUserInfo.getNickname().equals(existingUser.getNickName())) {
                existingUser.setNickName(wechatUserInfo.getNickname());
            }

            // 更新用户头像（如果微信头像有变化）
            if (StringUtils.hasText(wechatUserInfo.getHeadImgUrl()) &&
                    !wechatUserInfo.getHeadImgUrl().equals(existingUser.getAvatarUrl())) {
                existingUser.setAvatarUrl(wechatUserInfo.getHeadImgUrl());
            }

            userMapper.updateById(existingUser);
            log.info("更新微信用户登录信息: openid={}, userId={}", openid, existingUser.getId());
            return existingUser;
        } else {
            // 创建新用户
            UserDO newUser = new UserDO();
            newUser.setWxOpenid(openid);
            newUser.setNickName(StringUtils.hasText(wechatUserInfo.getNickname()) ?
                    wechatUserInfo.getNickname() : "微信用户_" + openid.substring(openid.length() - 8));
            // 设置用户头像
            if (StringUtils.hasText(wechatUserInfo.getHeadImgUrl())) {
                newUser.setAvatarUrl(wechatUserInfo.getHeadImgUrl());
            }
            return userService.createNewUserNormal(newUser);
        }
    }

    @Override
    public WechatAuthAccessToken getValidAccessToken(String code, String openid) {
        // 如果有openid，先尝试从缓存获取
        if (StringUtils.hasText(openid)) {
            WechatAuthAccessToken cachedToken = wechatTokenCacheService.getCachedAccessToken(openid);

            if (cachedToken != null) {
                // 检查token是否即将过期
                if (wechatTokenCacheService.isTokenExpiringSoon(openid)) {
                    log.info("缓存的token即将过期，尝试刷新: openid={}", openid);
                    try {
                        // 尝试刷新token
                        WechatAuthAccessToken refreshedToken = refreshAndCacheAccessToken(openid);
                        if (refreshedToken != null) {
                            return refreshedToken;
                        }
                        log.warn("刷新token失败，使用原有token: openid={}", openid);
                    } catch (Exception e) {
                        log.error("刷新token失败，使用原有token: openid={}", openid, e);
                    }
                }

                // 验证token有效性
                if (isAccessTokenValid(cachedToken.getAccessToken(), openid)) {
                    log.debug("使用缓存的有效token: openid={}", openid);
                    return cachedToken;
                } else {
                    log.info("缓存的token已失效，尝试刷新: openid={}", openid);
                    // token失效，删除缓存并尝试刷新
                    wechatTokenCacheService.removeCachedAccessToken(openid);
                    try {
                        WechatAuthAccessToken refreshedToken = refreshAndCacheAccessToken(openid);
                        if (refreshedToken != null) {
                            return refreshedToken;
                        }
                    } catch (Exception e) {
                        log.error("刷新token失败: openid={}", openid, e);
                    }
                }
            }
        }

        // 如果没有缓存或刷新失败，使用code获取新token
        if (StringUtils.hasText(code)) {
            log.info("使用code获取新token: code={}", code);
            WechatAuthAccessToken newToken = getAccessToken(code);
            if (newToken != null && StringUtils.hasText(newToken.getOpenid())) {
                // 缓存新获取的token
                wechatTokenCacheService.cacheAccessToken(newToken.getOpenid(), newToken);
                log.info("成功获取并缓存新token: openid={}", newToken.getOpenid());
                return newToken;
            }
        }

        throw new RuntimeException("无法获取有效的access_token");
    }

    @Override
    public WechatAuthAccessToken refreshAndCacheAccessToken(String openid) {
        if (!StringUtils.hasText(openid)) {
            throw new RuntimeException("openid不能为空");
        }

        // 从缓存获取refresh_token
        WechatAuthAccessToken cachedToken = wechatTokenCacheService.getCachedAccessToken(openid);
        if (cachedToken == null || !StringUtils.hasText(cachedToken.getRefreshToken())) {
            log.error("无法找到refresh_token，无法刷新: openid={}", openid);
            throw new RuntimeException("无法找到refresh_token");
        }

        try {
            // 刷新token
            WechatAuthAccessToken refreshedToken = refreshAccessToken(cachedToken.getRefreshToken());
            if (refreshedToken != null) {
                // 更新缓存
                wechatTokenCacheService.cacheAccessToken(openid, refreshedToken);
                log.info("成功刷新并缓存token: openid={}", openid);
                return refreshedToken;
            }
        } catch (Exception e) {
            log.error("刷新token失败: openid={}", openid, e);
            // 刷新失败，删除无效缓存
            wechatTokenCacheService.removeCachedAccessToken(openid);
            throw new RuntimeException("刷新token失败", e);
        }

        throw new RuntimeException("刷新token返回结果为空");
    }
}
